#[cfg(test)]
mod tests {
    use std::{
        panic,
        pin::Pin,
        sync::{atomic::Ordering, Arc},
        time::Duration,
    };

    use async_trait::async_trait;
    use openssl::{pkey::PKey, ssl::Ssl, x509::X509};
    use tokio::{io::AsyncWriteExt, net::TcpSocket, time::sleep};

    use crate::{
        config::ssl::{acceptor::SslAcceptorConf, connector::SslConnectorConf},
        iface::{AppHandle, AppManager},
        listener::{conf::ListenerConf, ArcListener, ListenerManager},
        openssl::{
            acceptor::CustomAcceptorBuilder, connector::CustomConnectorBuilder,
            stream::SslStream,
        },
        runtime::{RuntimeManager, PROCESS_EXIT},
        stream::Stream,
    };

    // TODO: 这里的证书和私钥是从 openresty 拷贝过来的, 后续应该换成我们自己的证书.

    pub const CERT_STR: &str = "
-----BEGIN CERTIFICATE-----
MIICqTCCAhICCQClDm1WkreW4jANBgkqhkiG9w0BAQUFADCBlzELMAkGA1UEBhMC
VVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28x
EjAQBgNVBAoMCU9wZW5SZXN0eTESMBAGA1UECwwJT3BlblJlc3R5MREwDwYDVQQD
DAh0ZXN0LmNvbTEgMB4GCSqGSIb3DQEJARYRYWdlbnR6aEBnbWFpbC5jb20wIBcN
MTQwNzIxMDMyMzQ3WhgPMjE1MTA2MTMwMzIzNDdaMIGXMQswCQYDVQQGEwJVUzET
MBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzESMBAG
A1UECgwJT3BlblJlc3R5MRIwEAYDVQQLDAlPcGVuUmVzdHkxETAPBgNVBAMMCHRl
c3QuY29tMSAwHgYJKoZIhvcNAQkBFhFhZ2VudHpoQGdtYWlsLmNvbTCBnzANBgkq
hkiG9w0BAQEFAAOBjQAwgYkCgYEA6P18zUvtmaKQK2xePy8ZbFwSyTLw+jW6t9eZ
aiTec8X3ibN9WemrxHzkTRikxP3cAQoITRuZiQvF4Q7DO6wMkz/b0zwfgX5uedGq
047AJP6n/mwlDOjGSNomBLoXQzo7tVe60ikEm3ZyDUqnJPJMt3hImO5XSop4MPMu
Za9WhFcCAwEAATANBgkqhkiG9w0BAQUFAAOBgQA4OBb9bOyWB1//93nSXX1mdENZ
IQeyTK0Dd6My76lnZxnZ4hTWrvvd0b17KLDU6JnS2N5ee3ATVkojPidRLWLIhnh5
0eXrcKalbO2Ce6nShoFvQCQKXN2Txmq2vO/Mud2bHAWwJALg+qi1Iih/gVYB9sct
FLg8zFOzRlYiU+6Mmw==
-----END CERTIFICATE-----";

    pub const KEY_STR: &str = "
-----BEGIN RSA PRIVATE KEY-----
MIICXgIBAAKBgQDo/XzNS+2ZopArbF4/LxlsXBLJMvD6Nbq315lqJN5zxfeJs31Z
6avEfORNGKTE/dwBCghNG5mJC8XhDsM7rAyTP9vTPB+Bfm550arTjsAk/qf+bCUM
6MZI2iYEuhdDOju1V7rSKQSbdnINSqck8ky3eEiY7ldKingw8y5lr1aEVwIDAQAB
AoGBANgB66sKMga2SKN5nQdHS3LDCkevCutu1OWM5ZcbB4Kej5kC57xsf+tzPtab
emeIVGhCPOAALqB4YcT+QtMX967oM1MjcFbtH7si5oq6UYyp3i0G9Si6jIoVHz3+
8yOUaqwKbK+bRX8VS0YsHZmBsPK5ryN50iUwsU08nemoA94BAkEA9GS9Q5OPeFkM
tFxsIQ1f2FSsZAuN/1cpZgJqY+YaAN7MSPGTWyfd7nWG/Zgk3GO9/2ihh4gww+7B
To09GkmW4QJBAPQOHC2V+t2TA98+6Lj6+TYwcGEkhOENfVpH25mQ+kXgF/1Bd6rA
nosT1bdAY+SnmWXbSw6Kv5C20Em+bEX8WjcCQCSRRjhsRdVODbaW9Z7kb2jhEoJN
sEt6cTlQNzcHYPCsZYisjM3g4zYg47fiIfHQAsfKkhDDcfh/KvFj9LaQOEECQQCH
eBWYEDpSJ7rsfqT7mQQgWj7nDThdG/nK1TxGP71McBmg0Gg2dfkLRhVJRQqt74Is
kc9V4Rp4n6F6baL4Lh19AkEA6pZZer0kg3Kv9hjhaITIKUYdfIp9vYnDRWbQlBmR
atV8V9u9q2ETZvqfHpN+9Lu6NYR4yXIEIRf1bnIZ/mr9eQ==
-----END RSA PRIVATE KEY-----
    ";

    pub struct TestApp {}

    impl TestApp {
        fn new() -> Self {
            TestApp {}
        }
    }

    #[async_trait]
    impl AppHandle for TestApp {
        async fn handle(&self, event: Stream, listener: ArcListener) {
            _ = listener;

            let cert = X509::from_pem(CERT_STR.as_bytes()).unwrap();
            let key = PKey::private_key_from_pem(KEY_STR.as_bytes()).unwrap();
            let mut conf = SslAcceptorConf::default();
            conf.set_leaf_cet(cert);
            conf.set_pkey(key);
            let runtime_conf = conf.to_runtime_conf(None).unwrap();

            let acceptor_ctx =
                CustomAcceptorBuilder::new(runtime_conf).build().unwrap();

            let ssl = Ssl::new(&acceptor_ctx).unwrap();
            let mut ssl_stream: SslStream<Stream> =
                SslStream::new(ssl, event).unwrap();
            let res = Pin::new(&mut ssl_stream).accept().await;
            println!("{:#?}", res);
            println!("success");
        }
    }

    #[test]
    fn test_ssl_acceptor() {
        // 测试框架会将worker runtime中的panic信息捕获.
        fn custom_panic_handler(info: &panic::PanicHookInfo) {
            if let Some(location) = info.location() {
                println!(
                    "real panic in {}:{}",
                    location.file(),
                    location.line()
                );
                panic!("paniced");
            }
        }

        panic::set_hook(Box::new(custom_panic_handler));

        RuntimeManager::init_main_runtime(1);
        RuntimeManager::init_worker_runtime(None, 1);

        RuntimeManager::main_runtime_block_on(async {
            AppManager::register_app(
                "test".to_string(),
                Arc::new(Box::new(TestApp::new())),
            );

            let mut conf = ListenerConf::default();
            conf.address = "127.0.0.1:6611".to_string();
            conf.app_name = "test".to_string();
            conf.validate().unwrap();

            ListenerManager::register_listener_by_conf(Arc::new(conf)).unwrap();
            ListenerManager::run();

            RuntimeManager::get_worker_runtime()
                .get_handle()
                .spawn(async {
                    let socket = TcpSocket::new_v4().unwrap();
                    let stream = socket
                        .connect("127.0.0.1:6611".parse().unwrap())
                        .await
                        .unwrap();

                    let s: Stream = stream.into();

                    let conf = SslConnectorConf::default();
                    let runtime_conf = conf.to_runtime_conf(None).unwrap();

                    let connector_ctx =
                        CustomConnectorBuilder::new(runtime_conf)
                            .build()
                            .unwrap();

                    let mut ssl = Ssl::new(&connector_ctx).unwrap();
                    ssl.set_hostname("www.aaa.com").unwrap();
                    let mut ssl_stream = SslStream::new(ssl, s).unwrap();

                    if let Err(e) = Pin::new(&mut ssl_stream).connect().await {
                        println!("{}", e);
                    }

                    Pin::new(&mut ssl_stream).shutdown().await.unwrap();

                    println!(
                        "stream {:#?} shutdown",
                        ssl_stream.get_ref().unique_id()
                    );

                    PROCESS_EXIT.store(true, Ordering::Relaxed);
                });

            let mut exit = false;
            loop {
                if PROCESS_EXIT.load(Ordering::Relaxed) {
                    println!("process done");
                    exit = true;
                }

                sleep(Duration::from_millis(100)).await;
                if exit {
                    break;
                }
            }
        });
    }
}
